<?php

abstract class Jf_Controller_Action_Abstract {

    public $actions = array();

    protected $_module;

    protected $_name = '';

    protected $_request = null;

    protected $_response = null;

    protected $_invokeArgs = array();

    protected $_view;

    protected $_dispatcher = null;

    public function __construct (Jf_Controller_Request_Abstract $request, Jf_Controller_Response_Abstract $response, array $invokeArgs = array()) {
        $this -> _request = $request;
        $this -> _response = $response;
        $this -> _invokeArgs = $invokeArgs;
        $this -> _module = $request -> getModuleName ();
        $this -> _name = get_class ($this);
        $this -> init ();
    }

    public function display ($tpl = null, $parameters = array()) {
        $script = $this -> getViewScript ($tpl);
        $this -> getView () -> display ($script, $parameters);
    }

    public function getPlugin ($plugin) {
        return $this -> getDispatcher () -> getPlugin ($plugin);
    }

    public function hasPlugin ($plugin) {
        return $this -> getDispatcher () -> hasPlugin ($plugin);
    }

    final public function forwardAction ($action, array $params = null) {
        $request = $this -> getRequest ();
        $module = $request -> getModuleName ();
        $controller = $request -> getControllerName ();
        $this -> forward ($action, $controller, $module, $params);
    }

    final public function forward ($action, $controller = null, $module = null, array $params = null) {
        $request = $this -> getRequest ();
        if (null !== $params) {
            $request -> setParams ($params);
        }
        if (null !== $controller) {
            $request -> setControllerName ($controller);
            if (null !== $module) {
                $request -> setModuleName ($module);
            }
        }
        $request -> setActionName ($action) -> setDispatched (false);
    }

    public function getInvokeArg ($key) {
        if (isset ($this -> _invokeArgs[$key])) {
            return $this -> _invokeArgs[$key];
        }
        return null;
    }

    public function getInvokeArgs () {
        return $this -> _invokeArgs;
    }

    public function getModuleName () {
        return $this -> _module;
    }

    public function getRequest () {
        return $this -> _request;
    }

    public function getDispatcher () {
        if ( ! $this -> _dispatcher instanceof Jf_Controller_Dispatcher_Interface) {
            $this -> _dispatcher = Jf_Controller_Dispatcher::getInstance ();
        }
        return $this -> _dispatcher;
    }

    public function getResponse () {
        return $this -> _response;
    }

    public function getViewScriptPath () {
        $view = $this -> getView ();
        return $view -> getScriptPath ();
    }

    public function init () {}

    public function preDispatch () {}

    public function getView () {
        if ( ! $this -> _view instanceof Jf_View_Interface) {
            $this -> getDispatcher () -> enableView ();
            $this -> _view = Jf_View::getView ();
            $this -> initViewScriptPath ();
        }
        return $this -> _view;
    }

    public function render ($tpl = null, $parameters = array()) {
        $script = $this -> getViewScript ($tpl);
        return $this -> getView () -> render ($script, $parameters);
    }

    public function renderScript ($script, $name = null) {
        $this -> getDispatcher () -> disableView ();
        $view = $this -> getView ();
        $this -> getResponse () -> appendBody ($view -> render ($script), $name);
    }

    public function redirect ($url) {
        $this -> getResponse () -> setRedirect ($url);
        $this -> getResponse () -> sendHeaders ();
        exit ();
    }

    public function setViewpath ($templateDir) {
        $view = $this -> getView ();
        $view -> setScriptPath ($templateDir);
    }

    public function initViewScriptPath () {
        $appPath = Jf_Global::get ('directory');
        $scriptPath = $appPath . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $this -> getRequest () -> getModuleName () . DIRECTORY_SEPARATOR . 'views';
        $this -> getView () -> setScriptPath ($scriptPath);
        if ($this -> hasPlugin ('layout') && $this -> getRequest () -> isGet () &&  ! $this -> getRequest () -> isXmlHttpRequest ()) {
            $layoutPath = $scriptPath . DIRECTORY_SEPARATOR . '_layouts';
            $this -> getPlugin ('layout') -> setLayoutPath ($layoutPath);
        }
    }

    protected function getViewScript ($action = null) {
        $request = $this -> getRequest ();
        if (null === $action) {
            $action = $request -> getActionName ();
        } elseif ( ! is_string ($action)) {
            throw new InvalidArgumentException ('Invalid action for view rendering');
        }
        $action = str_replace ('_', DIRECTORY_SEPARATOR, strtolower ($action));
        $script = $action . '.' . Jf_Global::get ('view_ext');
        $controller = $request -> getControllerName ();
        if ($controller != null) {
            $controller = str_replace ('_', DIRECTORY_SEPARATOR, strtolower ($controller));
        }
        $script = $controller . DIRECTORY_SEPARATOR . $script;
        return $script;
    }

    protected function renderByAjax ($script = null) {
        if ($this -> getRequest () -> isXmlHttpRequest ()) {
            if ($script == null) {
                $controller = strtolower ($this -> getRequest () -> getControllerName ());
                $controllerDir = str_replace ('_', '/', $controller);
                $script = "$controllerDir/_content.phtml";
            }
            $this -> renderScript ($script);
        }
    }

}
